﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace MyLib
{
    /// <summary>
    /// 类似于HTTP的服务器 通信协议也是HTTP简单处理 或者MsgPack来处理 或者JSON处理
    /// 多个Room 公用访问需要Await接口
    /// </summary>
    public class FPSServerMgr : Actor
    {
        private Dictionary<string, FPSServerInfo> freeServers = new Dictionary<string, FPSServerInfo>();
        private Dictionary<string, FPSServerInfo> usedServers = new Dictionary<string, FPSServerInfo>();
        private List<FPSServerInfo> connectedServer = new List<FPSServerInfo>();

        public override void Init()
        {
            base.Init();
            InitTcpServer();
        }

        /// <summary>
        /// 获取一个空的FPS服务器 
        /// 获取一个空闲的游戏服务器
        /// 主线程来管理
        /// 或者用加锁来访问
        /// 游戏主线程执行逻辑 
        /// 加锁可能死锁，但是逻辑简单访问速度快
        /// 异步不用加锁，但是逻辑复杂
        /// 要么确定资源都必须通过主线程来访问
        /// </summary>
        /// <returns></returns>
        public async Task<FPSServerInfo> GetServer()
        {
            await _messageQueue;
            //先启动网关再启动游戏服务器
            //游戏服务器尝试和网关建立连接
            LogHelper.Log2("GetFreeServerToClient:"+freeServers.Count);

            while(freeServers.Count <= 0)
            {
                //https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,291b6f82d3bd29c1
                //DelayPromise : Task<VoidTaskResult>   PromiseTask
                //TASK_STATE_WAITINGFORACTIVATION
                //private TimerHolder m_timer;
                //生成 GetServer 
                //    // internal helper function breaks out logic used by TaskCompletionSource
                //internal bool TrySetResult(TResult result)
                /*
                 * var cp = m_contingentProperties;
                if (cp != null) cp.SetCompleted();
 
                FinishStageThree(); Awaiter 触发执行
                TaskAwaiter:  OnCompletedInternal
                捕获Context 执行 上一次设置的Context  SetContinuationForAwait
                 TimerSetup( 
                 new TimerHolder(new TimerQueueTimer(callback, state, dueTime, period, ref stackMark))
                  m_executionContext 执行上下文  m_executionContext  class TimerQueue
                  线程Sleep即可 Room是单独的Thread
                  TaskAwaiter
                 // If there was no SynchronizationContext, then try for the current scheduler.
                    // We only care about it if it's not the default.
                    var scheduler = TaskScheduler.InternalCurrent;
                    if (scheduler != null && scheduler != TaskScheduler.Default)
                    {
                        tc = new TaskSchedulerAwaitTaskContinuation(scheduler, continuationAction, flowExecutionContext, ref stackMark);
                    }
                     if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext))
                    tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, continuationAction, flowExecutionContext, ref stackMark);
                      [SecurityCritical]
                     private static void PostAction(object state)
                     c.m_syncContext.Post(s_postCallback, c.m_action);
                     执行Post逻辑 Context的
                 */
                await Task.Delay(1000);
            }
            var first = freeServers.First();
            var ser = first.Value;
            freeServers.Remove(first.Key);
            //被使用了
            ser.state = FPSServerInfo.State.Used;
            usedServers.Add(ser.localInfo.GetHash(), ser);
            LogHelper.Log2("UsedServer:"+usedServers.Count+":"+freeServers.Count);
            return ser;
        } 



        private TcpNetServer netServer;
        private void InitTcpServer()
        {
            var tcpPort = ServerConfig.instance.configMap["FPSHttpServer"]["TcpPort"].AsInt;
            netServer = new TcpNetServer()
            {
                mainLoop = _messageQueue,
                port = tcpPort,
                OnNewConnect = (c) =>
                {
                    var ns = new FPSServerInfo();
                    ns.fpsConnect = c;
                    ns.mgr = this;
                    connectedServer.Add(ns);

                    c.handler = ns.HandleMsg;
                    c.ClosedEvtHandler = ns.OnClose;
                },
            };
            netServer.Start();
        }

        public void AddFreeServer(FPSServerInfo sinfo)
        {
            freeServers.Add(sinfo.localInfo.GetHash(), sinfo);
            LogHelper.Log2("AddFreeServer:"+sinfo.fpsRoomInfo+":"+freeServers.Count);
        }

        public void RemoveFPSServer(FPSServerInfo info)
        {
            connectedServer.Remove(info);
            if(info.state == FPSServerInfo.State.Init)
            {
                freeServers.Remove(info.localInfo.GetHash());
            }
            if(info.state == FPSServerInfo.State.Used)
            {
                usedServers.Remove(info.GetHash());
            }
        }
    }
}
